#include <iostream>
#include <algorithm>
#include <vector>

int const maxn = 100007;

int next[4 * maxn], end_point[4 * maxn], head[maxn];
int alloc = 1;

int indegree[maxn];

void add_edge(int x, int y)
{
	std::swap(x, y);
	end_point[alloc] = y; next[alloc] = head[x]; head[x] = alloc++;
	indegree[y]++;
}

struct node
{
	int x, y, id;
};

bool operator<(node const & a, node const & b)
{
	return a.y < b.y || (a.y == b.y && a.x < b.x);
}

std::istream & operator>>(std::istream & is, node & a)
{
	is >> a.x >> a.y;
	return is;
}

std::vector<node> da;
int n;

int main()
{
	std::ios::sync_with_stdio(false);
	std::cin >> n;
	da.resize(n);
	for (int i = 0; i < n; i++) {
		std::cin >> da[i];
		da[i].id = i;
	}

	int ground = n;
	std::sort(da.begin(), da.end());
	for (auto i : da) {
		if (!i.y) add_edge(i.id, ground);
		else {
			node tmp; tmp.x = i.x - 1; tmp.y = i.y - 1;
			auto it1 = std::lower_bound(da.begin(), da.end(), tmp);
			auto it2 = std::upper_bound(da.begin(), da.end(), tmp);
			if (it1 == it2 - 1) add_edge(i.id, it1->id);

			tmp.x = i.x;
			it1 = std::lower_bound(da.begin(), da.end(), tmp);
			it2 = std::upper_bound(da.begin(), da.end(), tmp);
			if (it1 == it2 - 1) add_edge(i.id, it1->id);

			tmp.x = i.x + 1;
			it1 = std::lower_bound(da.begin(), da.end(), tmp);
			it2 = std::upper_bound(da.begin(), da.end(), tmp);
			if (it1 == it2 - 1) add_edge(i.id, it1->id);
		}
	}

}

